home *** CD-ROM | disk | FTP | other *** search
- #ifndef lint
- static char rcsid[]="CUCL $Header: wdbm.c,v 2.3 86/11/18 08:07:37 pb Exp $";
- #endif lint
-
- THIS IS JUST INCLUDED IN THE DISTRIBUTION AS AN EXAMPLE
-
- PLEASE CONTACT ME FOR THE LATEST VERSION
-
- /*
- * This software may be used or copied by anyone so long as it is not sold
- * for profit, and that the gist of this header is retained.
- *
- * Anyone finding a bug/feature/extension should contact the author in the
- * first instance.
- *
- * (c) Piete Brooks <pb@cl.cam.ac.uk> Cambridge Univ Comp Lab, UK. Feb 1985
- *
- * $State: Exp $
- * $Log: wdbm.c,v $
- * Revision 2.3 86/11/18 08:07:37 pb
- * Overwrite with the REAL version .....
- *
- */
-
- /*
- * Compilation:
- *
- * cc wdbm -I<york header directory> -l<york library name>
- * eg cc wdbm -I/usr/src/x25 -lx25
- *
- * If only text->text is required, add -DTEXT_ONLY
- *
- * This was written for the dbm code I put into D2.2
- * I have been unable to aquire a pre-release copy of D2.2 from york or spider
- * to see what mods they have made to it, so this may need some mods.
- * If you have any problems, PLEASE MAIL ME & I'll try to fix them.
- *
- * I have not fully tested (if at all):
- *
- * non dbm use
- * many others
- *
- * but I repeat -- Please let ME know of any problems so I can fix them &
- * distribute fixes.
- */
-
- /* Usage: wdbm [options] [destination]
- *
- * normal use: wdbm
- *
- * This program takes a directory file (see netdir(5)), and generates a binary
- * version for direct access with dbm operations or a text version.
- * In the case of the binary, it stores the information three times:
- * the standard name, the abbreviated name & the address.
- * The names are stored with all the leading domains which match with the
- * current domain stripped.
- * The latter is infact only part of the address as defined by base_addr(addr)
- * so as to ensure that the suffices are ignored in the initial lookup.
- *
- * Source file format:
- *
- * #<anything> ignore this line
- *
- * <anythingelse> process this line
- *
- *
- * Piete Brooks, University Cambridge Computer Laboratory, Feb 85
- */
-
- #include "local.h"
- #include "netio.h"
- #include "tdir.h"
- #include "nets.h"
- #ifndef TEXT_ONLY
- #include "ndbm.h"
- #endif TEXT_ONLY
- #include <errno.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-
- /* Well, good old spider went & removed all the debug code !! */
- #ifndef deb
- /*
- * The debugging package:
- * By default have it ON: may be turned OFF in local.h
- */
- #ifdef NODEBUG
- #undef DEBUG
- #define deb(n, rest)
- #else NODEBUG
- #define DEBUG
- #endif NODEBUG
-
- #define D_USER 0
- #define D_ADDR 1
- #define D_NET 2
- #define D_SIZE (D_NET + 1)
-
- #ifndef D_DEF
- #define D_DEF D_USER
- #endif D_DEF
- #define COMMA ,
- int debug_v[D_SIZE];
- #define debug debug_v[D_DEF]
-
- /*
- SO: you can do: cc -DD_DEF=<x>
- or:
- #define D_DEF <x> in header
- */
- /*
- * Define a deb(n, text) macro, and COMMA (to be used in place of ',' in
- * all deb statements. Typical use is:
- * deb(10, "Simple text");
- * deb(20, "Complex text" COMMA arg1 COMMA arg2)
- */
- #ifndef NODEBUG
- #define deb(n, rest) if (debug > n) fprintf(stderr, rest)
- #define set_low_deb(x) { debug_v[D_ADDR] = x; debug_v[D_NET] = x; }
- #define deb_l(l, n, rest) if (debug_v[l] > n) fprintf(stderr, rest)
- #endif NODEBUG
- #endif deb
-
- /* In their wisdom, york/spider decided to make an incompatible change */
- #ifndef SIGNED_C
- #define SIGNED_C short
- #endif SIGNED_C
-
- extern errno;
-
- /* Table to convert from a network name (e.g. JANET) to a single letter */
- struct nets {
- char n_char;
- char *n_string;
- } nets[] = {
- { NETc_JANET, NETs_JANET },
- { NETc_PSS, NETs_PSS },
- { NETc_LOCAL, NETs_LOCAL },
- { NETc_IPSS, NETs_IPSS },
- { 0 }
- };
-
- #ifndef TEXT_ONLY
- DBM_t * dbm;
- #endif TEXT_ONLY
-
- char *gets(), *base_addr(), *strip_std(), *unstrip_std(), *index();
- struct tdirent *gettdadr(), *parse_directory_line();
-
- extern char *optarg;
- extern int getopt(), optind;
- char getopt_arg[] = "d:D:aco:Ortu";
- char USAGE[] = "Usage: %s [-d(ebug)] [-D(ebug)] [-n(ocompat)] [-c(ompress-off)]\n\t[-a(dd)] [-r(emove)] [-t(ext)] [-U(pdate)] [-o(utputfile)] [source]\n";
- char PAG[] = ".pag";
- char DIR[] = ".dir";
- char TEMP[] = "-t";
- char new_line[2048];
- char *nl_ptr;
-
- main(argc, argv)
- char **argv;
- {
- char line[2048];
- char split_line[2048];
- char name[2048];
- char data_buff[2048];
- char dummy[2048];
- char destination_filename[2048];
- char *out_filename;
- char *in_filename;
- #ifndef TEXT_ONLY
- Datum_t data;
- Datum_t key;
- Datum_t T_last;
- #endif TEXT_ONLY
- int fd;
- int store_failed = 0; /* how many times have dbm_add failed */
- int old_dir = 0; /* Is this an old format directory ? */
- int lineno; /* source line number */
- int c;
- char *commandname = *argv;
- int compress = 1; /* Should the JANET:0: -> J ? */
- #ifndef TEXT_ONLY
- int text = 0; /* am I producing text ? */
- #else TEXT_ONLY
- int text = 1;
- #endif TEXT_ONLY
- int upd = 0; /* should I update the DBM in situ */
- int replace = 0; /* am I replacing an entry */
- int add = 0; /* am I adding extra entries */
- int remove = 0; /* am I removng entries */
- int exists = 0; /* does the DBM exist already */
-
- struct stat sbuf;
- struct stat *sbp = &sbuf;
-
- #ifndef TEXT_ONLY
- data.dptr = data_buff;
- key.dptr = name;
- #endif TEXT_ONLY
-
- while ((c = getopt(argc, argv, getopt_arg)) != EOF)
- switch (c) {
- #ifdef DEBUG
- case 'd': debug = atoi(optarg); break;
- case 'D': set_low_deb(atoi(optarg)); break;
- #endif DEBUG
- case 't': text =1; deb(3, "text\n"); break;
- case 'c': compress= 0; deb(3, "nocompress\n"); break;
- case 'o': out_filename = optarg; break;
- case 'O': old_dir = 1; deb(3, "old format\n"); break;
- case 'r': remove = 1; deb(3, "remove\n"); break;
- case 'a': add = 1; deb(3, "add\n"); break;
- case 'u': upd = 1; deb(3, "update\n"); break;
- default: printf(USAGE, commandname); exit(1);
- }
-
- argc -= optind;
- argv += optind;
-
- /* If no output file, then use stout for text, else the std dbm */
- if (out_filename == CNULL)
- out_filename = (text) ? "-" : ADDRESSFILE;
-
- /* One file -- default input == output */
- if (argc > 0)
- in_filename = argv[0];
- else
- in_filename = (text) ? "-" : out_filename;
-
- strcpy(destination_filename, out_filename);
- out_filename = destination_filename;
-
- deb(2, "Process %s to %s\n" COMMA
- in_filename COMMA out_filename);
-
- /* Open the input file */
- if (strcmp(in_filename, "-")) {
- fclose(stdin);
- if (fopen(in_filename, "r") != stdin)
- die("Failed to open '%s' as stdin: ", in_filename);
- }
- if (text && strcmp(out_filename, "-")) {
- fclose(stdout);
- if (fopen(out_filename, "w") != stdout)
- die("Failed to open '%s' as stdout: ", out_filename);
- }
-
- #ifndef TEXT_ONLY
- /*
- for my sins check if db exists, if so open old one to add to
- the sin is assuming that if <dir> exists then <dir>.DIR/PAG
- does too (sigh)
- */
- if (!text)
- { if (!upd && !add && !stat(out_filename, sbp)) {
- /* DB exists: Do not process the working file !! Make a temp copy */
- deb(3, "creating new database...");
- strcat(out_filename, TEMP);
-
- /* And the two output files ... */
- strcpy(line, out_filename);
- strcat(line, PAG);
- fd = creat(line, 0777);
- if (fd < 0)
- die("Failed to creat %s: ", line);
- deb(3, "%s created OK\n" COMMA line);
- close(fd);
-
- strcpy(line, out_filename);
- strcat(line, DIR);
- fd = creat(line, 0777);
- if (fd < 0)
- die("Failed to creat %s: ", line);
- deb(3, "%s created OK\n" COMMA line);
- close(fd);
- exists = 0;
- }
- else {
- deb(3, "Using old database %s\n" COMMA out_filename);
- exists = 1;
- }
- if (!(dbm = ndbmopen(out_filename, 2, 0))) {
- fprintf(stderr, "Failed to open %s: ", out_filename);
- perror("");
- exit(1);
- }
- }
- #endif TEXT_ONLY
- deb(0,"setting domain\n");
- set_domain_default();
- deb(0, "domain set\n");
-
- /* Now process the data */
- for (lineno = 1; gets(line) != CNULL; lineno++) {
- struct tdirent *tdir;
-
- /* Comment ? Look for progmat. (none at the moment) */
- if (*line == '#') {
- if (text) printf("%s\n", line);
- continue;
- }
-
- #ifndef TEXT_ONLY
- /*
- * Just remove the key given
- */
- if (remove) {
- /* Ensure the KEY is correct */
- Datum_t D_last;
- key.dptr = line;
- deb(1, "deleting [%s]\n" COMMA key.dptr);
- key.dsize = strlen(key.dptr);
- if (dbmdelete(dbm, key) != 0)
- deb(0, "delete of %s failed\n" COMMA key.dptr);
- continue;
- }
- #endif TEXT_ONLY
-
- /* make a copy of the data and parse it */
- strcpy(split_line, line);
- if (tdir = parse_directory_line(split_line)) {
- char *addr_hash = base_addr(tdir->td_address);
- char compressed = 0;
- char known_net = 0;
- char name_[128];
- char abbrev_[128];
- char *name;
- char *abbrev;
- int relay;
- SIGNED_C prefix;
- SIGNED_C a_prefix;
-
- /* Replace 'X' with 'Y' if / in name */
- if (index(tdir->td_address, '/')) {
- char *change;
- if (change = index(tdir->td_services, X25SERVICE))
- *change = YBSERVICE;
- if (change = index(tdir->td_rev_services, X25SERVICE))
- *change = YBSERVICE;
- }
- #ifdef DIR_COMPAT
- if (old_dir) { /* Convert TS29->YB */
- char *change;
- if (change = index(tdir->td_services, 'T'))
- *change = YBSERVICE;
- if (change = index(tdir->td_rev_services, 'T'))
- *change = YBSERVICE;
- }
- #endif DIR_COMPAT
-
- /*
- * Now let's rebuild the line from scratch ....
- */
- if (compress)
- { struct nets *p;
-
- /* Known Network ? */
- for (p = nets; p->n_char; p++)
- if (! cistrcmp(p->n_string, tdir->td_network))
- { known_net = p->n_char;
- if (tdir->td_flags[TDFS_isunix] == 0 ||
- tdir->td_flags[TDFS_isunix] == TDF_isunix)
- compressed = known_net |
- ((tdir->td_flags[TDFS_isunix]) ?
- DBM_isunix : 0);
- break;
- }
- }
-
- unstrip_std(name_, sizeof name_, tdir->td_name, tdir->td_prefix);
- unstrip_std(abbrev_, sizeof abbrev_, tdir->td_abbrev, tdir->td_a_prefix);
- name = strip_std(name_, &prefix);
- abbrev = strip_std(abbrev_, &a_prefix);
-
- nl_ptr = new_line;
- if (compressed) adds("%c" COMMA compressed);
- else
- {
- /* The flags */
- if (!compress || tdir->td_flags[0])
- adds("%x", tdir->td_flags[0]);
- addcolon();
-
- /* The network */
- if (known_net) adds("%c", known_net);
- else adds("%s", tdir->td_network);
- addcolon();
- }
-
- /* The services */
- if (! cistrcmp(tdir->td_services, tdir->td_rev_services))
- adds("%s", tdir->td_services);
- else adds("%s|%s", tdir->td_services,
- tdir->td_rev_services);
- addcolon();
-
- /* The names */
- if (! cistrcmp(name, abbrev))
- adds("%s", name);
- else adds("%s|%s", name, abbrev);
- addcolon();
-
- /* The address */
- adds("%s", tdir->td_address);
- addcolon();
-
- /* The preficies */
- if (prefix == a_prefix)
- adds("%d", prefix);
- else adds("%d|%d", prefix, a_prefix);
- addcolon();
-
- /* The application relays */
- for (relay=0; relay < MAX_AR && tdir->td_ars[relay]; relay++)
- { int len = strlen(new_line);
- adds("%s%s", (relay) ? "|" : "", tdir->td_ars[relay]);
- if (len >= MAX_DIRLEN -2)
- { printf("Remove `%s' from %s\n", new_line+len+1, name);
- new_line[len] = '\0';
- }
- }
- addcolon();
-
- /* The comment */
- /* If this is about to overrun, then chop it ! */
- if (strlen(new_line) + strlen(tdir->td_text) >= MAX_DIRLEN-1)
- { static char elipsis[] = "...";
- int spare = MAX_DIRLEN-1 - strlen(new_line) - sizeof elipsis;
- printf("Truncate comment field `%s' for %s\n", tdir->td_text, name);
- if (spare > 0)
- adds("%.*s%s", spare, tdir->td_text, elipsis);
- }
- else adds("%s", tdir->td_text);
-
- deb(1, "%3d <%s> -> <%s>\n" COMMA lineno COMMA line COMMA new_line);
-
- strcpy(line, new_line);
-
- if (strlen(line) >= MAX_DIRLEN-1) {
- printf("Bad line %5d ignored: %d (>%d) chars `%s'\n",
- lineno, strlen(line), MAX_DIRLEN - 2, line);
- /*??*/
- continue;
- }
-
- if (text)
- printf("%s\n", line);
- #ifndef TEXT_ONLY
- else {
- strcpy(split_line, line);
- parse_directory_line(split_line);
-
- strcpy(key.dptr, tdir->td_name);
-
- /* Anything in the FORWARD direction ? */
- if (tdir->td_services) {
- /* Ensure the KEY is correct */
- deb(1, " [%s]\n" COMMA key.dptr);
- key.dsize = strlen(key.dptr);
- if (key.dsize)
- { T_last = dbmfetch(dbm, key);
- if (T_last.dptr) {
- if (upd == 0) {
- deb(5, "<< add to\n%s\n" COMMA T_last.dptr);
- strcpy(data.dptr, T_last.dptr);
- strcat(data.dptr, "\n");
- strcat(data.dptr, line);
- deb(5, "%d bytes>>\n" COMMA strlen(data.dptr));
- }
- else {
- strcpy(data.dptr, line);
- deb(5, "replacing %s\n with %s\n" COMMA T_last.dptr COMMA data.dptr);
- replace = 1;
- }
- }
- else
- strcpy(data.dptr, line);
-
- data.dsize = strlen(data.dptr) + 1;
- if (data.dsize > 1000)
- deb(0, "store ...");
- if (dbmstore(dbm, key, data, 1)) {
- store_failed++;
- if (data.dsize > 1000)
- deb(0, "Failed\n");
- deb(10, "Store failed on `%s'\n" COMMA data.dptr);
- }
- if (data.dsize > 1000)
- deb(0, "Failed\n");
- deb(50, "[[ Store OK on `%s' ]]\n" COMMA data.dptr);
- }
- else printf("Null long forward key in `%s' -- ignored\n", line);
- /* abbreviated form? */
- if (tdir->td_abbrev && tdir->td_abbrev != tdir->td_name &&
- strcmp(tdir->td_abbrev, tdir->td_name)) {
- strcpy(key.dptr, tdir->td_abbrev);
- key.dsize = strlen(key.dptr);
- if (key.dsize)
- { T_last = dbmfetch(dbm, key);
- if (T_last.dptr) {
- if (upd == 0) {
- deb(5, "<< add to\n%s\n" COMMA T_last.dptr);
- strcpy(data.dptr, T_last.dptr);
- strcat(data.dptr, "\n");
- strcat(data.dptr, line);
- deb(5, "%d bytes>>\n" COMMA strlen(data.dptr));
- }
- else {
- strcpy(data.dptr, line);
- deb(5, "replacing %s\n with %s\n" COMMA T_last.dptr COMMA data.dptr);
- replace = 1;
- }
- }
- else
- strcpy(data.dptr, line);
-
- data.dsize = strlen(data.dptr) + 1;
- if (data.dsize > 1000)
- deb(0, "store ...");
- if (dbmstore(dbm, key, data, 1)) {
- store_failed++;
- if (data.dsize > 1000)
- deb(0, "Failed\n");
- deb(10, "Store failed on `%s'\n" COMMA data.dptr);
- }
- if (data.dsize > 1000)
- deb(0, "Failed\n");
- deb(50, "[[ Store OK on `%s' ]]\n" COMMA data.dptr);
- }
- else printf("Null abbreviated forward key in `%s' -- ignored\n", line);
-
- }
- }
-
- /* Anything in the REVERSE direction ? */
- if (*tdir->td_rev_services) {
- if (addr_hash != CNULL && *addr_hash) {
- /* Ensure the KEY is correct */
- strcpy(key.dptr, addr_hash);
- deb(1, " [%s] " COMMA key.dptr);
- key.dsize = strlen(key.dptr);
- T_last = dbmfetch(dbm, key);
- if (T_last.dptr) {
- if (replace == 0) {
- deb(5, "<< add to (%s)\n%s\n" COMMA addr_hash COMMA T_last.dptr);
- strcpy(data.dptr, T_last.dptr);
- strcat(data.dptr, "\n");
- strcat(data.dptr, line);
- deb(5, "%d bytes>>\n" COMMA strlen(data.dptr));
- }
- else {
- strcpy(data.dptr, line);
- deb(5, "replaced [%s]\n with [%s]\n" COMMA T_last.dptr COMMA data.dptr);
- replace = 0;
- }
- }
- else
- strcpy(data.dptr, line);
-
- data.dsize = strlen(data.dptr) + 1;
- if (data.dsize > 1000)
- deb(0, "store ...");
- if (dbmstore(dbm, key, data, 1)) {
- store_failed++;
- if (data.dsize > 1000)
- deb(0, "Failed\n");
- deb(10, "Store failed on `%s'\n" COMMA data.dptr);
- }
- if (data.dsize > 1000)
- deb(0, "Failed\n");
- deb(50, "[[ Store OK on `%s' ]]\n" COMMA data.dptr);
- }
- else
- deb(0, "No address in `%s'\n" COMMA line);
- }
- deb(1, "\n");
- }
- #endif TEXT_ONLY
- }
- else
- printf("Bad line %5d at field %d: '%s'\n",
- lineno, fd, line);
- }
- #ifndef TEXT_ONLY
- if (store_failed)
- printf("Store failed %d time%s\n",
- store_failed, (store_failed == 1) ? "" : "s");
-
- /* Now rename it */
- if (!text && !exists) {
- /* created in temp files rather than just updating */
- strcpy(line, out_filename);
- strcat(line, PAG);
- strcpy(split_line, out_filename);
- split_line[strlen(split_line) - (sizeof TEMP - 1)] = 0;
- strcat(split_line, PAG);
- mv(split_line, line);
- strcpy(line, out_filename);
- strcat(line, DIR);
- strcpy(split_line, out_filename);
- split_line[strlen(split_line) - (sizeof TEMP - 1)] = 0;
- strcat(split_line, DIR);
- mv(split_line, line);
- }
- #endif TEXT_ONLY
- exit(0);
- }
-
- addcolon()
- {
- *nl_ptr++ = ':';
- *nl_ptr = '\0';
- }
-
- /*VARARGS 1*/
- adds(format, a1,a2,a3,a4,a5,a6)
- char *format;
- { char *p;
- sprintf(nl_ptr, format, a1,a2,a3,a4,a5,a6);
- while (p = index(nl_ptr, ':'))
- { *p = COLON;
- nl_ptr = p+1;
- }
- while (*nl_ptr) nl_ptr++;
- }
-
- #ifndef TEXT_ONLY
- mv(to, from)
- char *to,
- *from;
- {
- if (unlink(to) && errno != ENOENT) {
- fprintf(stderr, "Failed to unlink %s: ", to);
- perror("");
- }
- else
- if (link(from, to) == 0)
- unlink(from);
- else {
- fprintf(stderr, "Failed to move %s to %s: ", from, to);
- perror("");
- }
- }
- #endif TEXT_ONLY
-
- /* VARARGS1 */
- die(s, a, b, c, d, e, f, g)
- char *s;
- {
- fprintf(stderr, s, a, b, c, d, e, f, g);
- perror("");
- exit(1);
- }
-